home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 3: CDPD 3 / Almathera Ten on Ten - Disc 3: CDPD3.iso / scope / 001-025 / scopedisk16 / cw11 / cw.c < prev    next >
C/C++ Source or Header  |  1995-03-18  |  10KB  |  352 lines

  1.  
  2. /*
  3.     cw - one-shot stream editor
  4.     Version 1.1
  5.     Copyright (C) 1988 Daniel Elbaum
  6.  
  7.     New in Version 1.1:
  8.  
  9.         -Fixed an output buffering problem wherein
  10.          the i/o buffer got flushed twice (it's a
  11.          long way to CON: ;{))
  12.  
  13.         -Fixed a case wherein a few bytes of memory
  14.          were left unfreed when the target file
  15.          couldn't be found.
  16.  
  17.         -Added a special-case replacement string arg,
  18.          "\0", to specify a null replacement string.
  19.          This feature avoids difficulties with the
  20.          quoting/argument-parsing conventions of
  21.          various command interpreters.
  22. */
  23.  
  24. #include <stdio.h>
  25. #include <libraries/dos.h>
  26. #include <libraries/dosextens.h>
  27. #include <exec/memory.h>
  28.  
  29. #ifndef BUFSIZ
  30. #define BUFSIZ  (512)
  31. #endif
  32. #define LSIZ    (258)
  33. #ifndef MIN
  34. #define MIN(x, y)   ((x)>(y)?(y):(x))
  35. #endif
  36.  
  37. UBYTE iobuf[BUFSIZ];
  38. int iosofar=0;
  39. int nflag;
  40.  
  41. UBYTE *strchr();         /* defined in cwlib.asm */
  42. #define ismeta(x)       (strchr("*?.^$", (x)))
  43. #define plur(x)         ((x)==1?'\0':'s')       /* pluralizes a number  */
  44.  
  45.  
  46. struct finfo {
  47.         UBYTE *name;             /* file name                    */
  48.         UBYTE *mp;               /* file buffer                  */
  49.         struct FileHandle *fh;   /* file handle                  */
  50.         ULONG n;                 /* bytes in file                */
  51.         };
  52.  
  53. main(c, v)
  54. UBYTE *v[];
  55. {
  56.         register n, usage=0;
  57.  
  58.         register UBYTE **vp;
  59.         UBYTE sub[LSIZ], targ[LSIZ];
  60.         UBYTE obu[BUFSIZ];
  61.  
  62.         if (c<4) usage++;
  63.         else if (v[1][0]=='-')
  64.                 if (v[1][1]=='n'){
  65.                         if (!v[1][2]) nflag=1;
  66.                         else if (!(nflag=atoi(&(v[1][2])))) usage++;
  67.                         v++;
  68.                 }
  69.                 else usage++;
  70.         if (usage){
  71.                 puts("Usage: cw [-nN] target replacement files...");
  72.                 puts("N is the maximum number of substitutions to make");
  73.                 exit(-1);
  74.         }
  75.         prepstrings(v[1], v[2], targ, sub);     /* map metachars        */
  76.         for (vp=&v[3]; *vp; ++vp){
  77.                 strcpy(obu, *vp);
  78.                 strcat(obu, ": ");
  79.                 fputs(obu, stdout);
  80.                 n=cw(targ, sub, *vp);
  81.                 if (n>=0){
  82.                     sprintf(obu, "%d change%c", n, plur(n));
  83.                     puts(obu);
  84.                 }
  85.                 else puts("error");
  86.         }
  87.         if (n<0) exit(-1);
  88.         exit(0);
  89. }
  90.  
  91. cw(ip, op, nam)
  92. register UBYTE *ip, *op;
  93. UBYTE *nam;
  94. {
  95.         register UBYTE *iop;
  96.         register ULONG n;
  97.         register struct FileHandle *fh;
  98.         register ilen;
  99.         register rpt;
  100.         int olen;
  101.         int nchanges=0;
  102.         struct finfo f;
  103.  
  104.         olen=strlen(op);
  105.         setmem(&f, sizeof(f), '\0');
  106.         f.name=nam;
  107.  
  108.         if (fillbuf(&f)<0) {cleanup(&f); return(-1);}
  109.         if (!(rpt=nflag)) rpt=-1;
  110.         iop=f.mp;
  111.         n=f.n;
  112.         fh=f.fh;
  113.         while (n){
  114.                 if (rpt&&(ilen=regcmp(ip, iop))){
  115.                         if (bufout(fh, op, olen)){
  116.                                 puts("write error--FILE TRASHED");
  117.                                 return(-1);
  118.                         }
  119.                         iop+=ilen;
  120.                         n-=ilen;
  121.                         if (n<0) puts("DS error");
  122.                         nchanges++;
  123.                         if (rpt>0) if (nchanges>=rpt) rpt=0;
  124.                 }
  125.                 else {
  126.                         if (bufout(fh, iop++, 1)) puts("write error");
  127.                         --n;
  128.                 }
  129.         }
  130.         cleanup(&f);
  131.         return(nchanges);
  132. }
  133.  
  134. cleanup(sp)
  135. struct finfo *sp;
  136. {
  137.         Write(sp->fh, iobuf, iosofar);  /* flush output buffer  */
  138.         iosofar=0;
  139.         if (sp->fh) Close(sp->fh);
  140.         if (sp->mp) FreeMem(sp->mp, sp->n);
  141. }
  142.  
  143. prepstrings(ip, op, ipbu, opbu)
  144. UBYTE *ip, *op;
  145. register UBYTE *opbu, *ipbu;
  146. {
  147.         register UBYTE *foop;
  148.         register hat=0, cash=0;
  149.  
  150.         /* special case: op = "\0"  */
  151.         if (op[0]=='\\'&&op[1]=='0'&&op[2]=='\0') op[0]='\0';
  152.         /* special case: target=='^$'   */
  153.         if ((ip[0]=='^')&&(ip[1]=='$')&&(ip[2]=='\0')){
  154.                 movmem(ipbu, "\n\n\0", 3);
  155.                 *opbu='\n'; opbu[1]='\0';
  156.                 if (strlen(op)){
  157.                         strcat(opbu, op);
  158.                         strcat(opbu, "\n");
  159.                 }
  160.         }
  161.         strcpy(ipbu, ip);
  162.         escape(ipbu);
  163.         /* ... and here's something for the commoners   */
  164.         for (foop=ipbu; *foop; ++foop)
  165.                 if (*foop==0xDE) {++hat; *foop='\n';}
  166.                 else if (*foop==0xA4) {++cash; *foop='\n';}
  167.         if (hat) *opbu++ = '\n';
  168.         *opbu='\0';
  169.         strcat(opbu, op);
  170.         if (cash) strcat(opbu, "\n");
  171.         return(0);
  172. }
  173.  
  174. /*
  175.         set high bit of non-escaped metacharacters
  176.         and convert escape sequences
  177. */
  178.  
  179. escape(s)
  180. register UBYTE *s;
  181. {
  182.         UBYTE bu[256];
  183.         register UBYTE *op;
  184.         register esc, i, c;
  185.  
  186.         op=s;
  187.         for (esc=i=0; *s; ++s){
  188.                 if (!esc){
  189.                         if (ismeta(*s)) bu[i++]=*s|0x80;
  190.                         else if (*s=='\\') ++esc;
  191.                         else bu[i++]=*s;
  192.                         continue;
  193.                 }
  194.                 else{
  195.                         switch(*s){
  196.                                 case 't': c='\t'; break;
  197.                                 case 'n': c='\n'; break;
  198.                                 case 'r': c='\r'; break;
  199.                                 case 'b': c='\b'; break;
  200.                                 case 'f': c='\f'; break;
  201.                                 default: c=*s;
  202.                             }
  203.                         bu[i++]=c;
  204.                         esc=0;
  205.                 }
  206.         }
  207.         bu[i]='\0';
  208.         strcpy(op, bu);
  209.         return(0);
  210. }
  211.  
  212. /*
  213.         Hand-buffer output.
  214.         Works for cnt==0; theoretically for cnt>BUFSIZ.
  215. */
  216.  
  217. bufout(fh, buf, cnt)
  218. register struct FileHandle *fh;
  219. register UBYTE *buf;
  220. register cnt;
  221. {
  222.         register n=0, off;
  223.  
  224.         do{
  225.                 off=n;          /* keep track of #chars written */
  226.                 cnt-=n;         /* subtract #written from # to write    */
  227.                 n=MIN(cnt, BUFSIZ-iosofar);     /* chunk to put in iobu */
  228.                 movmem(buf+off, iobuf+iosofar, n);
  229.                 iosofar+=n;
  230.                 if (iosofar>=BUFSIZ){
  231.                         if (Write(fh, iobuf, iosofar)<0) return(-1);
  232.                         iosofar=0;
  233.                 }
  234.         } while (cnt);
  235.         return(0);
  236. }
  237.  
  238. /*
  239.         Allocate space for a whole-file buffer, fill it,
  240.         then truncate the file and open for writing.
  241.         Name passed in sp->name;
  242.         File handle returned in sp->fh;
  243.         Length of file returned in sp->n;
  244.         Address of buffer returned in sp->mp;
  245. */
  246.  
  247. fillbuf(sp)
  248. register struct finfo *sp;
  249. {
  250.         register fibsiz;
  251.         struct FileLock *l;
  252.         struct FileInfoBlock *fi;
  253.         UBYTE *AllocMem();
  254.         struct FileHandle *Open();
  255.         struct FileLock *Lock();
  256.  
  257.         fibsiz=sizeof(struct FileInfoBlock);
  258.         if (!(fi=(struct FileInfoBlock *)AllocMem(fibsiz, MEMF_PUBLIC)))
  259.                 return(-1);
  260.         if (!(l=Lock(sp->name, ACCESS_WRITE))) {
  261.                 FreeMem(fi, fibsiz);
  262.                 return(-1);
  263.                 }
  264.         if (!(Examine(l, fi))) {FreeMem(fi, fibsiz); UnLock(l); return(-1);}
  265.         sp->n=fi->fib_Size;
  266.         FreeMem(fi, fibsiz);
  267.         UnLock(l);
  268.         if (!(sp->mp=AllocMem(sp->n, MEMF_PUBLIC))) return(-1);
  269.         if (!(sp->fh=Open(sp->name, MODE_OLDFILE))){
  270.                 FreeMem(sp->mp, sp->n);
  271.                 return(-1);
  272.                 }
  273.         if (Read(sp->fh, sp->mp, sp->n)!=sp->n){
  274.                 Close(sp->fh);
  275.                 FreeMem(sp->mp, sp->n);
  276.                 return(-1);
  277.                 }
  278.         Close(sp->fh);
  279.         if (!(sp->fh=Open(sp->name, MODE_NEWFILE))) {
  280.                 FreeMem(sp->mp, sp->n);
  281.                 return(-1);
  282.                 }
  283.         return(0);
  284. }
  285.  
  286. regcmp(p1, p2)
  287. register UBYTE *p1, *p2;
  288. {
  289.         register len;
  290.         register out=0;
  291.  
  292.         for (len=0; p2[len]; ++p1, ++len){
  293.                 if (!(*p1)) break;
  294.                 if (!(*p1&0x80))
  295.                         if (regchar(*p1, p2[len])) {len=0; break;}
  296.                         else continue;
  297.                 switch(*p1&0xFF){
  298.                         case 0xAA:      /* *    */
  299.                                 if (!*++p1) {++out; break;}
  300.                                 while (p2[len]&®char(*p1, p2[len]))
  301.                                         ++len;
  302.                                 if (!p2[len]) ++out;
  303.                                 break;
  304.                         case 0xBF:      /* ?    */
  305.                                 break;
  306.                         case 0xAE:      /* .    */
  307.                                 if (p2[len]!=' ') break;
  308.                         default:        /* AE may fall through  */
  309.                                 len=0; ++out;
  310.                                 break;
  311.                 }
  312.                 if (out) break;
  313.         }
  314.         if (*p1) len=0;
  315.         return(len);
  316. }
  317.  
  318. /*
  319.         0 means c1 matches c2
  320. */
  321.  
  322. regchar(c1, c2)
  323. register c1, c2;
  324. {
  325.         if (c1==c2) return(0);
  326.         if ((c1=='\n'||c1=='\r')&&(c2=='\n'||c2=='\r')) return(0);
  327.         if (!(c1&0x80)) return(1);
  328.         switch(c1&0xFF){
  329.                 case 0xAA:      /* *--falls through    */
  330.                 case 0xBF:      /* ?    */
  331.                         return(0);
  332.                 case 0xAE:      /* .--falls through    */
  333.                         if (c2!=' ') return(0);
  334.                 default:
  335.                         return(1);
  336.         }
  337.         /* NOTREACHED   */
  338. }
  339.  
  340. UBYTE *
  341. strchr(s, c)
  342. UBYTE *s;
  343. {
  344.     if (s)
  345.         while (*s)
  346.             if (*s==c) return(s);
  347.             else s++;
  348.     return(NULL);
  349. }
  350.  
  351.  
  352.